#include <iostream>
#define LU 0
#define UP 1
#define LE 2
struct array{
int* arr;
int length;
array(int* _arr, int _length): arr(_arr), length(_length){}
int operator[](int ind){
return arr[ind];
}
};
template <typename T>
struct twoPoint{
T *p1, *p2;
twoPoint(T* _p1, T* _p2): p1(_p1), p2(_p2) {}
~twoPoint(){
delete p1;
delete p2;
}
};
struct Table{
int m, n;
int** table;
Table(int _m, int _n): m(_m), n(_n){
this->table=new int*[this->m];
for(int i=0; i<this->m; ++i){
this->table[i]=new int[this->n];
}
}
~Table(){
for(int i=0; i<this->m; ++i) delete[] this->table[i];
delete[] this->table;
}
int* operator[](int n){
return this->table[n];
}
};
twoPoint<Table> LCS(array X, array Y){
int m=X.length, n=Y.length;
Table* b=new Table(m, n);
Table* c=new Table(m+1, n+1);
for(int i=0; i<n+1; ++i){
(*c)[i][0]=0;
}
for(int j=0; j<m+1; ++j){
(*c)[0][j]=0;
}
for(int i=0; i<m; ++i){
for(int j=0; j<n; ++j){
if(X[i]==Y[j]){
(*c)[i+1][j+1]=(*c)[i][j]+1;
(*b)[i][j]=LU;
} else if((*c)[i][j+1]>=(*c)[i+1][j]){
(*c)[i+1][j+1]=(*c)[i][j+1];
(*b)[i][j]=UP;
} else{
(*c)[i+1][j+1]=(*c)[i+1][j];
(*b)[i][j]=LE;
}
}
}
return twoPoint<Table>(c, b);
}
void PrintLCS(Table* b, array X, int i, int j){
if(i==-1 || j==-1) return;
if((*b)[i][j]==LU){
PrintLCS(b, X, i-1, j-1);
std::cout<<X[i]<<' ';
} else if((*b)[i][j]==UP) PrintLCS(b, X, i-1, j);
else PrintLCS(b, X, i, j-1);
}
int main(void){
int x[]={1, 2, 3, 2, 4, 1, 2};
int y[]={2, 4, 3, 1, 2, 1};
int szx=sizeof(x)/sizeof(int), szy=sizeof(y)/sizeof(int);
array X(x, szx), Y(y, szy);
twoPoint<Table> res=LCS(X, Y);
PrintLCS(res.p2, X, szx-1, szy-1);
return 0;
}